/**
 * @class $$.sql.reader.Pagination
 * 使用start/limited的方式的分页类。
 */
$$.sql.reader.Pagination = {
	constructor : function(){
		this.pageSize = Number(Request.QueryString('limit')()) || this.pageSize;
		this.startNum = Number(Request.QueryString('start')()) || this.startNum;
	}
	
	/**
	 * 每页显示记录笔数，或者说读取多少笔的记录。如不指定则为pageSize。
	 * @type {Number} pageSize
	 */
	,pageSize : 8

	/**
	 * 如不指定则为零，表示从第一笔记录开始。
	 * @type {Number} startNum
	 */
	,startNum : 0
	
	/**
	 * 符合当前查询条件的记录数。
	 * @type {Number} totalCount。
	 */
	,totalCount : 0
	
	/**
	 * 符合当前查询条件的总页数 = totalCount / pageSize
	 * @type {Number}
	 */
	,pages : 0
	
	/**
	 * 页码
	 * @type {Number} page
	 */
	,pageNo : null

	/**
	 * Why？

	 * 结论1：Select * 语句对速度影响很大。
	 * select * from Adab 用时：35940  (共57个字段)
	 * select xhjm,xm,xjztdm,bdm,nj,dwdm from Adab  用时 4186
	 * select xhjm,xm  from Adab  用时1626
	 * select xm from Adab   用时830
	 * 可以看得出每增加一个字段，时间会增加几乎是一倍。
	 * 另外，返回的数据的长度也会影响时间：如 select sfzh from Adab 用时1580 几乎与select xhjm,xm from Adab相同。
	 * 因此，返回的数据量是影响速度最关键的因素。网络上的数据传送成了执行SQL最大的性能问题。
	 * 执行一个selec dwdm,count(xhjm) from Adab的语句，用时106 要汇总计算，但传送数据少，因此速度很快。
	 * @ASP Only
	 * @param  {String} id_fieldName 排序的字段
	 * @return {Object} pagination
	 */
	,renderPage : (function(){
		var 
		 removeFields	= /(?:SELECT)\s+(.*)\s+(?:FROM)\s+(.+)\s?/i
		,hasSort		= /(\s+ORDER\s+BY\s+[\w\.]+)\s?(ASC|DESC)?/i
		,hasWhere		= /\s+WHERE\s+/i;

		/**
		 * @static
		 * @private
		 * @ASP Only
		 * @return {String}
		 * 优化一下，先不要id选好记录，选好后，跳到那一页，根据id读取。
		 */
		function getQuickSql(querySql){
			if(!querySql){
				throw '没有查询的SQL！';
			}
			/**
			 * 欲查询的SQL，即分页前的SQL。
			 * @type {String}
			 */
			this.querySql = querySql;	// 先保存一下。
			
	   		var arr = querySql.match(removeFields);
			return querySql.replace(arr[1], 'news.ID'); // id only
		}
	    
	    /**
	     * @private
	     * @ASP Only
	     * @param   {ado.rs} rs
	     * @param	{String} querySql
	     * @return  {String}
	     */
	    function getCurrentSql(rs, querySql){
			var  
			 IDs		= []
			,i			= 0
			,pageSize	= rs.pageSize;
			
			do {
				IDs.push(rs('id').value);
//					Response.Write("<p>每条记录信息：" + rs("id")  + "</p>");
				i++;
				rs.movenext();
			}while (!rs.Eof && ( i < pageSize));
			
			IDs	= (hasWhere.test(querySql) ?　" WHERE " : " WHERE ") + "  news.ID = " + IDs.join(' OR news.ID = ')
			
			if(!hasSort.test(querySql)){
				 return querySql + IDs;
			}else{
				 IDs += " $1 ASC "; // 必须相反，与原来的ORDER BY！
				 return querySql.replace(hasSort, IDs);  
			}
	    }
	    
		/**
		 * 分页的核心函数，返回 pagination 对象。转换 start/limit 分页方式 为 ado 的 absolutepage/pagesize 分页。
		 * @param  {Number} start
		 * @param  {Number}	pageSize
		 * @param  {Number}	totalCount
		 * @return {Object}
		 * @private
		 * @static
		 */
		function page(start, pageSize, totalCount){
			var 
			 // 计算分页总数。
			 pages = totalCount % pageSize ? Math.floor(totalCount / pageSize) + 1 : totalCount / pageSize
		     // 获取当前的页码。通过 start 计算得在第几页。
		    ,pageNo  = start / pageSize + 1
			/*
			 // pageNo的另一种解法
			var	 
				 pageNo		= (this.startNum / pageSize) + 1
				,pageNo		= pageNo || 1
				,pageNo		= (pageNo - totalCount) > 0 ? totalCount : pageNo
			*/
			,lastOffset = (pageNo - 2) * pageSize
			,isBOF		= lastOffset < 0
			,isEOF		= (pageNo * pageSize) > totalCount
			,nextOffset = isEOF
			             ? (pageNo - 1) * pageSize 
			             : (pageNo * pageSize);
	
			return {
				 totalCount	: totalCount		// 符合条件的记录总数。
				,start		: start				// 从第几笔记录开始偏移（offset）。
				,pageSize	: pageSize			// 每页多少笔记录？也可以认为是 偏移数 
				,pageNo		: pageNo			// 当前页码，即第几页。
				,pages		: pages				// 总页数。
				,lastOffset : lastOffset		// 跳到前一页（offset的方式）
				,nextOffset : nextOffset		// 跳到后一页（offset的方式）
				,isBOF		: isBOF				// 是否在最头一页（boolean）
				,isEOF		: isEOF				// 是否在最尾一页（boolean）
			};
		}
		
		/**
		 * @param {String} querySql
		 */
		return function(querySql, id_fieldName){
			var 
			// 为求记录总数而优化的SQL，即分页后的SQL。当前页数据的SQL
			 rs		  = new ActiveXObject("ADODB.Recordset")
			,quickSql = getQuickSql.call(this, querySql);
			
			rs.Open(quickSql, this.getConnObj(), 1 ,1);
			
			if(rs.EOF && rs.BOF){
				Response.write('没有记录');
				throw '没有记录';
			}else{
				var
			     pagination 	 = page(this.startNum, this.pageSize, rs.recordcount)
			    ,uiBar			 = Object.create($$.sql.reader.Pagination.barController)
			    ,currentPageSql;
			    
				 rs.pagesize     = pagination.pageSize
				,rs.absolutepage = pagination.pageNo
			    ,currentPageSql	 = getCurrentSql(rs, this.querySql); // 求当前页数据的SQL。
			    
			    rs.close();
			    
			    for(var i in pagination)uiBar[i] = pagination[i];
			}
			
		    return {
		         sql 	: currentPageSql
		        ,count  : pagination.totalCount
		        , html  : uiBar.render()
		    };  
		}
	})()
};

/**
 * This is a controller.
 * @class $$.sql.reader.Pagination.barController
 */
$$.sql.reader.Pagination.barController = {
	/**
	 * 返回true表示存在除了start以外还有其他的参数。
	 * @return {Boolean}
	 */
     hasQueryStr : function (){
        var req = Request.QueryString;
        if(req.Count > 0){
            if(req.Count == 1 && req('start').Count){
                return false; // 只有 start 的参数
            }
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * 返回QueryString
     * @todo
     * @return {String}
     */
    ,getQueryString : function (){
        var arr = [], QueryObj = {};
        
        var key, v;
        for(var e = new Enumerator(Request.QueryString); !e.atEnd(); e.moveNext()){
            key = e.item().toString();
            v   = Request.QueryString(key)(); // MS ASP这里好奇怪，不加()不能返回字符串
        
            /*
            v = unescape(decodeURI(v));
            
            if( v == 'true' )  v = true;
            if( v == 'false' ) v = false;
            */
            //if(isNum.test(v))  v = Number(v);
            
            QueryObj[key] = v;
        }
        if( QueryObj.start || QueryObj.start === 0 ){
            delete QueryObj.start;
        }
        for(var i in QueryObj){
            arr.push(i + '=' + QueryObj[i]);
        }
        return arr.join('&');        
    }
    
	/**
	 * @private
	 * @type {String}
	 */
	,el : '<li><a href="{0}" title="{1}">{2}</a></li>'
	
    // 上一页
    ,renderBOF : function(){
        var urlP = "?start={0}";
        
        if(this.hasQueryStr()){
            urlP += "&" + this.getQueryString(); 
        }
        
	    if(this.isBOF){
	    	return this.el.format(urlP.format(0), "首页" , "首页");
	    }else{
	    	return this.el.format(urlP.format(this.lastOffset), "下一页", "前页");
	    }
    }
                
    // 下一页
    ,renderEOF : function(){
        var urlP = "?start={0}";
        
        if(this.hasQueryStr()){
            urlP += "&" + this.getQueryString(); 
        }
           
	    if(this.isEOF){
	    	return this.el.format(urlP.format(this.nextOffset), "末页" , "末页");
	    }else{
	    	return this.el.format(urlP.format(this.nextOffset), "后一页", "后页");
	    }
    }

    ,renderBar : function(){
        var link = {
             href   : "?start={0}"
            ,title  : ""
            ,text   : ""
        };
        if(this.hasQueryStr()){
            link.href += "&" + this.getQueryString(); 
        }
        
        var e, html, links = [];
        var page;
        for(var i = 0, j = this.pages; i < j; i++){
            page    = i + 1;
            e       = {};
            
            for(var i in link){
            	e[i]= link[i];
            }
            e.href  = e.href.format( i * this.pageSize); // 倍数关系
            e.text  = page;
            e.title = "-->" + page;
            
            html    = this.el.format(e.href, e.title, e.text);
            
            if(page == this.pageNo){
                html = html.replace("<li", "<li class=\"highlight\"");
            }
            links.push(html);
        }
        return links.join('\n');
    }
    
	/**
	 * @return {String}
	 */
	,render : function(){
	    this.el = this.renderBOF() + this.renderBar() + this.renderEOF();
	    return $$.tpl.fillData($$.cfg.edk.edk_tpl.selectSingleNode('//pagingBar/div').xml, this);
	}
};